/**
********************************************************************************
@file     unit_test.h
@brief    对文件的简要说明
@details  对文件的详细说明
@author   jcai
@date     2024-09-08 19:22:56
@copyright Copyright &copy; 2024 wy1107412334@163.com All rights reserved
@version  v0.0.8

\n Email:  wy1107412334@163.com
\n Blog:   None
\n Github: https://github.com/wy1107412334
\n Gitee:  https://gitee.com/git.git1107412334.com

********************************************************************************
@note
None.
********************************************************************************
@attention
None.
********************************************************************************
@verbatim
@endverbatim
********************************************************************************
@par 修订记录
- jcai, 2024-09-21
  - 给校验指针的函数的 act 与 exp 加上修饰符 const
- jcai, 2024-09-21
  - 新增函数 unit_test_failed()
- jcai, 2024-09-17
  - 新增函数 unit_test_result_get()
- jcai, 2024-09-14
  - 新增如下类型的API的原型:
    - 校验指针相等与不相等
    - 校验实际值小于预期值
    - 校验实际值小于等于预期值
    - 校验实际值大于预期值
    - 校验实际值大于等于预期值
- jcai, 2024-09-14
  - 为数据类型与宏增加注释
- jcai, 2024-09-10
  - 修改函数 ut_verify_string_eq() 的原型
- jcai, 2024-09-10
  - 交换验证结果函数的 exp 与 act 这两个参数的位置
- jcai, 2024-09-08 19:22:56
  - 首次编写

********************************************************************************
*/

#ifndef __UNIT_TEST_H__
#define __UNIT_TEST_H__


/* 头文件导入区 ------------------------------------------------------------- */

#include <stdbool.h>
#include <stdio.h>
#include "signal_linked_list.h"


#ifdef __cplusplus
extern "C"
{
#endif

/**
@addtogroup UNIT_TEST
@brief unit_test modules
@{
*/


/* 条件编译定义 ------------------------------------------------------------- */





/* 模块输入API接口。即对外部少量依赖模块的API接口 --------------------------- */




/* 全局宏定义 --------------------------------------------------------------- */

#define UT_FUT_PREFIX       __unit_test_
#define UT_CUT_(a, b)       a ## b
#define UT_CUT(a, b)        UT_CUT_(a, b)
#define UT_FUT_VARNAME(fut) UT_CUT(UT_FUT_PREFIX, fut)


/**
声明保存待测试的FUT的变量

@param fut  FUT的名字
*/
#define UT_EXTERN_FUT_VARNAME(fut)  extern ut_cases_info_t UT_FUT_VARNAME(fut)
/**
定义保存待测试的FUT的变量

@param fut  FUT的名字
*/
#define UT_DEFINE_FUT_VARNAME(fut)  ut_cases_info_t UT_FUT_VARNAME(fut)

/**
将符号/标识符转换为字符串

@param sym  要转换为字符串的符号/标识符
*/
#define UT_STR(sym) # sym
/**
将宏的值转换为字符串

@param funcname  一个宏的名字
*/
#define UT_FUNC_STR(funcname)   UT_STR(funcname)

/**
注册FUT到测试库中

@param libname  测试库的名字，其数据类型为 ut_lib_t
@param futname  待测试的FUT的名字
@note 这里的 futname 与宏 UT_EXTERN_FUT_VARNAME() 的参数 fut 是一致的
*/
#define UT_FUT_REGISTER(libname, futname)   \
    unit_test_fut_register(&libname, & UT_FUT_VARNAME(futname))

/**
注册测试用例

@param tc  测试用例的id
@param futEntry  测试用例的入口函数
@param checkCount  此测试用例要检查的项目数量
@note 这里的 tc 一般与宏 UT_FUT_ENTRY() / UT_FUT_NAME() 的参数 tcId 是一样的
*/
#define UT_TEST_CASE_REG(tc, futEntry, checkCount)  { \
    {0},            \
    UT_FUNC_STR(UT_CUT3(__FUT__, _, tc)),     \
    futEntry,       \
    checkCount,     \
    0,              \
    false           \
    }

#define UT_CUT3__(a, b, c)      a ## b ## c
#define UT_CUT3_(a, b, c)       UT_CUT3__(a, b, c)
#define UT_CUT3(a, b, c)        UT_CUT3_(a, b, c)

/**
测试用例的入口函数的名字

@param tcId  是测试用例的id
@note 依赖实现FUT的测试用例的源文件中定义的宏 \_\_FUT\_\_ ，
这个宏就是待测试的FUT的名字
*/
#define UT_FUT_NAME(tcId)   UT_CUT3(testCase_, __FUT__, tcId)
/**
测试用例的入口函数的原型

@param tcId  是测试用例的id
@note 依赖实现FUT的测试用例的源文件中定义的宏 \_\_FUT\_\_ ，
这个宏就是待测试的FUT的名字
*/
#define UT_FUT_ENTRY(tcId)  \
    void UT_FUT_NAME(tcId)(void)


/* 全局数据类型定义 --------------------------------------------------------- */

/**
测试用例入口
*/
typedef void (* case_entry)(void);

/**
保存测试用例的信息
*/
typedef struct
{
    UT_SL_NODE      node;
    const char *    caseName;       /*!< 测试用例的名字 */
    case_entry      futEntry;       /*!< 测试用例的入口函数 */
    uint32_t        checkCount;     /*!< 测试用例要检测的项目数量 */
    uint32_t        verifiedCount;  /*!< 测试用例已经校验的项目的数量 */
    bool            isSuccess;      /*!< 测试用例的执行结果 */
} ut_case_t;


typedef enum
{
    ERROR = -1,
    OK = 0,
} STATUS;

/**
设定待测函数的执行环境
*/
typedef STATUS (* fut_setup)(void);
/**
清理待测函数的执行环境
*/
typedef case_entry fut_cleanup;

/**
保存待测函数的测试用例的信息
*/
typedef struct
{
    const char *    futName;    /*!< 待测函数的名字 */
    fut_setup       futSetup;   /*!< 设定待测函数的执行环境的函数 */
    fut_cleanup     futCleanup; /*!< 清理待测函数的执行环境的函数 */
    UT_SL_NODE      node;       /*!< 用于 ut_lib_t 中 futList 的节点 */
    UT_SL_NODE      failedNode; /*!< 用于 ut_lib_t 中 failedList 的节点 */
    ut_case_t *     cases;      /*!< 指向待测函数的测试用例数组的首地址 */
    uint32_t        caseNum;    /*!< cases 指向的数组的元素数量 */
    uint32_t        flags;      /*!< 标志此待测试FUT是否测试成功:
                                 *  - bit0置位表示FUT的 futSetup 执行失败
                                 *  - bit1置位表示FUT的测试用例执行失败
                                 */
} ut_cases_info_t;


/**
保存测试库的信息

@note
一个源文件或组件即为一个测试库，里面保存了所有要测试的函数的测试用例信息
*/
typedef struct
{
    const char *    libName;    /*!< 测试库的名字 */
    const char *    sourcePath; /*!< 组件名或源文件的路径 */
    UT_SL_NODE      node;
    UT_SL_LIST      futList;    /*!< 保存所有待测函数的链表 */
    UT_SL_LIST      failedList; /*!< 保存所有测试失败的函数的链表 */
    uint32_t        caseTotalNum;   /*!< 本测试库下测试用例的总数 */
} ut_lib_t;




/* 全局变量声明区 ----------------------------------------------------------- */







/* 全局函数声明区 ----------------------------------------------------------- */


extern void unit_test_init(void);
extern void unit_test_fut_register(ut_lib_t * lib, ut_cases_info_t * fut);
extern void unit_test_lib_register(ut_lib_t * lib);
extern void unit_test_run(void);
extern bool unit_test_result_get(void);
extern void unit_test_exit(void);

extern void unit_test_failed(const char * msg);

extern bool ut_verify_bool_eq(bool act, bool exp, const char * msg);
extern bool ut_verify_i8_eq(int8_t act, int8_t exp, const char * msg);
extern bool ut_verify_u8_eq(uint8_t act, uint8_t exp, const char * msg);
extern bool ut_verify_i16_eq(int16_t act, int16_t exp, const char * msg);
extern bool ut_verify_u16_eq(uint16_t act, uint16_t exp, const char * msg);
extern bool ut_verify_i32_eq(int32_t act, int32_t exp, const char * msg);
extern bool ut_verify_u32_eq(uint32_t act, uint32_t exp, const char * msg);
extern bool ut_verify_i64_eq(int64_t act, int64_t exp, const char * msg);
extern bool ut_verify_u64_eq(uint64_t act, uint64_t exp, const char * msg);
extern bool ut_verify_f32_eq(float act, float exp, const char * msg);
extern bool ut_verify_f64_eq(double act, double exp, const char * msg);
extern bool ut_verify_string_eq(const char * act, const char * exp, const char * msg);
extern bool ut_verify_buffer_eq(void * act, void * exp, uint32_t explen, const char * msg);
extern bool ut_verify_ptr_eq(const void * act, const void * exp, const char * msg);

extern bool ut_verify_bool_ne(bool act, bool exp, const char * msg);
extern bool ut_verify_i8_ne(int8_t act, int8_t exp, const char * msg);
extern bool ut_verify_u8_ne(uint8_t act, uint8_t exp, const char * msg);
extern bool ut_verify_i16_ne(int16_t act, int16_t exp, const char * msg);
extern bool ut_verify_u16_ne(uint16_t act, uint16_t exp, const char * msg);
extern bool ut_verify_i32_ne(int32_t act, int32_t exp, const char * msg);
extern bool ut_verify_u32_ne(uint32_t act, uint32_t exp, const char * msg);
extern bool ut_verify_i64_ne(int64_t act, int64_t exp, const char * msg);
extern bool ut_verify_u64_ne(uint64_t act, uint64_t exp, const char * msg);
extern bool ut_verify_f32_ne(float act, float exp, const char * msg);
extern bool ut_verify_f64_ne(double act, double exp, const char * msg);
extern bool ut_verify_string_ne(const char * act, const char * exp, uint32_t explen, const char * msg);
extern bool ut_verify_buffer_ne(void * act, void * exp, uint32_t explen, const char * msg);
extern bool ut_verify_ptr_ne(const void * act, const void * exp, const char * msg);

extern bool ut_verify_i8_lt(int8_t act, int8_t exp, const char * msg);
extern bool ut_verify_u8_lt(uint8_t act, uint8_t exp, const char * msg);
extern bool ut_verify_i16_lt(int16_t act, int16_t exp, const char * msg);
extern bool ut_verify_u16_lt(uint16_t act, uint16_t exp, const char * msg);
extern bool ut_verify_i32_lt(int32_t act, int32_t exp, const char * msg);
extern bool ut_verify_u32_lt(uint32_t act, uint32_t exp, const char * msg);
extern bool ut_verify_i64_lt(int64_t act, int64_t exp, const char * msg);
extern bool ut_verify_u64_lt(uint64_t act, uint64_t exp, const char * msg);
extern bool ut_verify_f32_lt(float act, float exp, const char * msg);
extern bool ut_verify_f64_lt(double act, double exp, const char * msg);

extern bool ut_verify_i8_le(int8_t act, int8_t exp, const char * msg);
extern bool ut_verify_u8_le(uint8_t act, uint8_t exp, const char * msg);
extern bool ut_verify_i16_le(int16_t act, int16_t exp, const char * msg);
extern bool ut_verify_u16_le(uint16_t act, uint16_t exp, const char * msg);
extern bool ut_verify_i32_le(int32_t act, int32_t exp, const char * msg);
extern bool ut_verify_u32_le(uint32_t act, uint32_t exp, const char * msg);
extern bool ut_verify_i64_le(int64_t act, int64_t exp, const char * msg);
extern bool ut_verify_u64_le(uint64_t act, uint64_t exp, const char * msg);
extern bool ut_verify_f32_le(float act, float exp, const char * msg);
extern bool ut_verify_f64_le(double act, double exp, const char * msg);

extern bool ut_verify_i8_gt(int8_t act, int8_t exp, const char * msg);
extern bool ut_verify_u8_gt(uint8_t act, uint8_t exp, const char * msg);
extern bool ut_verify_i16_gt(int16_t act, int16_t exp, const char * msg);
extern bool ut_verify_u16_gt(uint16_t act, uint16_t exp, const char * msg);
extern bool ut_verify_i32_gt(int32_t act, int32_t exp, const char * msg);
extern bool ut_verify_u32_gt(uint32_t act, uint32_t exp, const char * msg);
extern bool ut_verify_i64_gt(int64_t act, int64_t exp, const char * msg);
extern bool ut_verify_u64_gt(uint64_t act, uint64_t exp, const char * msg);
extern bool ut_verify_f32_gt(float act, float exp, const char * msg);
extern bool ut_verify_f64_gt(double act, double exp, const char * msg);

extern bool ut_verify_i8_ge(int8_t act, int8_t exp, const char * msg);
extern bool ut_verify_u8_ge(uint8_t act, uint8_t exp, const char * msg);
extern bool ut_verify_i16_ge(int16_t act, int16_t exp, const char * msg);
extern bool ut_verify_u16_ge(uint16_t act, uint16_t exp, const char * msg);
extern bool ut_verify_i32_ge(int32_t act, int32_t exp, const char * msg);
extern bool ut_verify_u32_ge(uint32_t act, uint32_t exp, const char * msg);
extern bool ut_verify_i64_ge(int64_t act, int64_t exp, const char * msg);
extern bool ut_verify_u64_ge(uint64_t act, uint64_t exp, const char * msg);
extern bool ut_verify_f32_ge(float act, float exp, const char * msg);
extern bool ut_verify_f64_ge(double act, double exp, const char * msg);

/**
addtogroup UNIT_TEST
@}
*/

#ifdef __cplusplus
}
#endif
#endif /* !__UNIT_TEST_H__ */


/*********************************** END OF FILE ******************************/
